from flask import Blueprint, render_template, request, jsonify, current_app, send_file
from app.services.crawler import CrawlerService
from app.services.pdf_generator import PDFService
from app.services.deep_crawler import DeepCrawler
from app.services.pdf_converter import PDFConverter
import logging
import sqlite3
import os
import shutil
from bs4 import BeautifulSoup
import pdfkit
import tempfile
import time
from datetime import datetime
import requests

# 创建蓝图
bp = Blueprint('main', __name__)

# 配置日志
logger = logging.getLogger(__name__)

# PDF生成配置
PDF_CONFIG = {
    'page-size': 'A4',
    'margin-top': '20mm',
    'margin-right': '20mm',
    'margin-bottom': '20mm',
    'margin-left': '20mm',
    'encoding': 'UTF-8',
    'no-outline': None,
    'enable-local-file-access': None
}

def generate_pdf_from_html(html_content, output_path):
    """从HTML内容生成PDF文件
    
    Args:
        html_content (str): HTML内容
        output_path (str): 输出PDF文件路径
        
    Returns:
        bool: 是否生成成功
    """
    try:
        # 创建临时HTML文件
        with tempfile.NamedTemporaryFile(suffix='.html', delete=False, mode='w', encoding='utf-8') as f:
            f.write(html_content)
            temp_html_path = f.name

        # 生成PDF
        pdfkit.from_file(temp_html_path, output_path, options=PDF_CONFIG)
        
        # 删除临时HTML文件
        os.unlink(temp_html_path)
        
        return True
    except Exception as e:
        logger.error(f"生成PDF失败: {str(e)}")
        return False

@bp.route('/')
def index():
    """首页"""
    try:
        # 获取分页参数
        page = request.args.get('page', 1, type=int)
        per_page = 10  # 每页显示10条记录
        
        # 连接数据库
        conn = sqlite3.connect(os.path.join(current_app.root_path, '..', 'data', 'app.db'))
        conn.row_factory = sqlite3.Row
        cursor = conn.cursor()
        
        # 获取总记录数
        cursor.execute('SELECT COUNT(*) FROM articles')
        total = cursor.fetchone()[0]
        
        # 计算总页数
        total_pages = (total + per_page - 1) // per_page
        
        # 获取当前页的文章列表
        offset = (page - 1) * per_page
        cursor.execute('''
            SELECT id, title, author, create_time, content, pdf_path
            FROM articles 
            ORDER BY create_time DESC 
            LIMIT ? OFFSET ?
        ''', (per_page, offset))
        
        articles = []
        for row in cursor.fetchall():
            # 处理文章内容，生成预览
            content = row['content']
            if content:
                # 使用BeautifulSoup解析HTML内容
                soup = BeautifulSoup(content, 'html.parser')
                
                # 移除所有script和style标签
                for script in soup(["script", "style"]):
                    script.decompose()
                
                # 获取文本内容
                text = soup.get_text()
                
                # 限制预览长度为150个字符
                preview = text[:150] + '...' if len(text) > 150 else text
                
                # 保留部分HTML标签的预览
                content_preview = f'<div class="preview-text">{preview}</div>'
                
                # 如果有图片，添加第一张图片的预览
                img = soup.find('img')
                if img and img.get('src'):
                    content_preview += f'<img src="{img["src"]}" class="preview-image">'
            else:
                content_preview = '<div class="preview-text">暂无内容</div>'
            
            articles.append({
                'id': row['id'],
                'title': row['title'],
                'author': row['author'],
                'create_time': row['create_time'],
                'content_preview': content_preview,
                'pdf_path': row['pdf_path']
            })
        
        conn.close()
        
        return render_template('index.html',
                             articles=articles,
                             current_page=page,
                             total_pages=total_pages)
                             
    except Exception as e:
        current_app.logger.error(f"获取文章列表失败: {str(e)}")
        return jsonify({
            'code': 1,
            'message': f'获取文章列表失败: {str(e)}'
        }), 500

@bp.route('/api/articles', methods=['GET'])
def get_articles():
    """获取文章列表"""
    try:
        page = request.args.get('page', 1, type=int)
        per_page = request.args.get('per_page', 10, type=int)
        
        # 查询文章
        pagination = Article.query.order_by(Article.create_time.desc()).paginate(
            page=page, per_page=per_page, error_out=False)
        
        articles = pagination.items
        
        return jsonify({
            'code': 0,
            'message': 'success',
            'data': {
                'total': pagination.total,
                'pages': pagination.pages,
                'current_page': page,
                'articles': [article.to_dict() for article in articles]
            }
        })
    except Exception as e:
        logger.error(f"获取文章列表失败: {str(e)}")
        return jsonify({
            'code': 500,
            'message': f'获取文章列表失败: {str(e)}'
        })

@bp.route('/api/articles/collect', methods=['POST'])
def collect_articles():
    """采集文章API"""
    try:
        data = request.get_json()
        if not data or not all(k in data for k in ['token', 'cookie', 'fakeid']):
            logger.error("参数不完整")
            return jsonify({'error': '参数不完整'}), 400
            
        logger.info(f"开始采集文章，参数: token={data['token'][:10]}..., cookie={data['cookie'][:10]}..., fakeid={data['fakeid']}")
        
        # 清除环境变量中的代理设置
        if 'http_proxy' in os.environ:
            del os.environ['http_proxy']
        if 'https_proxy' in os.environ:
            del os.environ['https_proxy']
        if 'HTTP_PROXY' in os.environ:
            del os.environ['HTTP_PROXY']
        if 'HTTPS_PROXY' in os.environ:
            del os.environ['HTTPS_PROXY']
        
        try:
            crawler = CrawlerService(
                token=data['token'],
                cookie=data['cookie'],
                fakeid=data['fakeid']
            )
            
            # 采集文章
            articles = crawler.collect_articles()
            logger.info(f"成功采集到 {len(articles)} 篇文章")
            
        except requests.exceptions.ProxyError as e:
            logger.error(f"代理错误: {str(e)}")
            return jsonify({
                'code': 500,
                'message': '代理设置错误，请检查系统代理设置'
            }), 500
        except requests.exceptions.SSLError as e:
            logger.error(f"SSL错误: {str(e)}")
            return jsonify({
                'code': 500,
                'message': 'SSL证书验证失败，请检查网络设置'
            }), 500
        except requests.exceptions.ConnectionError as e:
            logger.error(f"连接错误: {str(e)}")
            return jsonify({
                'code': 500,
                'message': '网络连接失败，请检查网络设置'
            }), 500
        except Exception as e:
            logger.error(f"采集文章失败: {str(e)}", exc_info=True)
            return jsonify({
                'code': 500,
                'message': f'采集文章失败: {str(e)}'
            }), 500
        
        # 连接数据库
        db_path = os.path.join(current_app.root_path, '..', 'data', 'app.db')
        logger.info(f"连接数据库: {db_path}")
        conn = sqlite3.connect(db_path)
        cursor = conn.cursor()
        
        # 处理每篇文章
        processed_articles = []
        for article in articles:
            try:
                # 检查文章内容
                if not article.get('content'):
                    logger.warning(f"文章 {article.get('title')} 内容为空")
                    continue
                    
                # 保存到数据库
                cursor.execute('''
                    INSERT INTO articles (title, content, content_url, author, create_time)
                    VALUES (?, ?, ?, ?, datetime('now'))
                ''', (
                    article.get('title', ''),
                    article.get('content', ''),
                    article.get('url', ''),
                    article.get('author', '微信公众号')
                ))
                
                article_id = cursor.lastrowid
                logger.info(f"文章 {article.get('title')} 已保存到数据库，ID: {article_id}")
                
                processed_articles.append({
                    'id': article_id,
                    'title': article.get('title', '')
                })
                    
            except Exception as e:
                logger.error(f"处理文章失败: {str(e)}", exc_info=True)
                continue
        
        # 提交更改
        conn.commit()
        logger.info("数据库更改已提交")
        
        # 获取最新的文章列表
        cursor.execute('''
            SELECT id, title, author, create_time, content_url
            FROM articles
            ORDER BY create_time DESC
            LIMIT 10
        ''')
        
        latest_articles = []
        for row in cursor.fetchall():
            latest_articles.append({
                'id': row[0],
                'title': row[1],
                'author': row[2],
                'create_time': row[3],
                'content_url': row[4]
            })
        
        conn.close()
        logger.info("数据库连接已关闭")
        
        return jsonify({
            'code': 0,
            'message': '采集成功',
            'data': {
                'processed_count': len(processed_articles),
                'articles': latest_articles
            }
        })
        
    except Exception as e:
        logger.error(f"采集文章失败: {str(e)}", exc_info=True)
        return jsonify({
            'code': 500,
            'message': f'采集文章失败: {str(e)}'
        }), 500

@bp.route('/api/generate-pdf/<int:article_id>', methods=['POST'])
def generate_pdf(article_id):
    """生成PDF
    
    Args:
        article_id (int): 文章ID
        
    Returns:
        json: 生成结果
    """
    try:
        # 连接数据库
        conn = sqlite3.connect(os.path.join(current_app.root_path, '..', 'data', 'app.db'))
        conn.row_factory = sqlite3.Row
        cursor = conn.cursor()
        
        # 查询文章
        cursor.execute('''
            SELECT title, content, author, create_time, content_url
            FROM articles
            WHERE id = ?
        ''', (article_id,))
        
        row = cursor.fetchone()
        if not row:
            conn.close()
            return jsonify({
                'code': 404,
                'message': '文章不存在'
            }), 404
            
        article = {
            'title': row['title'],
            'content': row['content'],
            'author': row['author'],
            'create_time': row['create_time'],
            'content_url': row['content_url']
        }
        
        # 生成PDF文件名
        timestamp = datetime.now().strftime('%Y%m%d_%H%M%S')
        pdf_filename = f"{article_id}_{timestamp}.pdf"
        pdf_dir = os.path.join(current_app.root_path, '..', 'data', 'pdfs')
        os.makedirs(pdf_dir, exist_ok=True)
        pdf_path = os.path.join(pdf_dir, pdf_filename)
        
        # 生成PDF的HTML内容
        pdf_html = f'''<!DOCTYPE html>
<html lang="zh-CN">
<head>
    <meta charset="UTF-8">
    <title>{article['title']}</title>
    <style>
        body {{
            font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif;
            line-height: 1.6;
            color: #333;
            padding: 20px;
        }}
        .article-header {{
            margin-bottom: 30px;
            padding-bottom: 20px;
            border-bottom: 1px solid #eee;
        }}
        .article-title {{
            font-size: 24px;
            font-weight: bold;
            color: #2c3e50;
            margin-bottom: 15px;
        }}
        .article-meta {{
            color: #666;
            font-size: 14px;
        }}
        .article-content {{
            font-size: 16px;
            line-height: 1.8;
        }}
        .article-content img {{
            max-width: 100%;
            height: auto;
            margin: 15px 0;
        }}
        .article-content p {{
            margin-bottom: 1.2em;
        }}
        .article-footer {{
            margin-top: 30px;
            padding-top: 20px;
            border-top: 1px solid #eee;
            color: #666;
            font-size: 14px;
        }}
        /* 覆盖微信文章的隐藏样式 */
        .article-content .rich_media_content {{
            visibility: visible !important;
            opacity: 1 !important;
        }}
        .article-content section {{
            margin-bottom: 1em;
        }}
        .article-content span[leaf] {{
            display: block;
            margin-bottom: 0.5em;
        }}
    </style>
</head>
<body>
    <div class="article-header">
        <h1 class="article-title">{article['title']}</h1>
        <div class="article-meta">
            <span>作者：{article['author']}</span>
            <span style="margin-left: 20px;">发布时间：{article['create_time']}</span>
        </div>
    </div>
    
    <div class="article-content">
        {article['content']}
    </div>
    
    <div class="article-footer">
        <p>原文链接：{article['content_url']}</p>
    </div>
</body>
</html>'''
        
        # 配置wkhtmltopdf
        config = pdfkit.configuration(wkhtmltopdf=r'D:\Program Files\wkhtmltopdf\bin\wkhtmltopdf.exe')
        
        # 设置PDF选项
        options = {
            'page-size': 'A4',
            'margin-top': '20mm',
            'margin-right': '20mm',
            'margin-bottom': '20mm',
            'margin-left': '20mm',
            'encoding': 'UTF-8',
            'no-outline': None,
            'enable-local-file-access': None
        }
        
        # 生成PDF
        pdfkit.from_string(pdf_html, pdf_path, options=options, configuration=config)
        
        # 更新数据库中的PDF路径
        cursor.execute('''
            UPDATE articles
            SET pdf_path = ?
            WHERE id = ?
        ''', (pdf_filename, article_id))
        conn.commit()
        
        return jsonify({
            'code': 0,
            'message': 'success',
            'data': {
                'pdf_path': pdf_filename
            }
        })
            
    except Exception as e:
        logger.error(f"生成PDF失败: {str(e)}")
        return jsonify({
            'code': 500,
            'message': f'生成PDF失败: {str(e)}'
        }), 500
    finally:
        if 'conn' in locals():
            conn.close()

@bp.route('/api/pdfs/clean', methods=['POST'])
def clean_pdfs():
    """清理PDF"""
    try:
        # 获取请求参数
        data = request.get_json()
        days = data.get('days', 7)
        
        # 创建PDF服务
        pdf_service = PDFService()
        
        # 清理PDF
        count = pdf_service.clean_old_pdfs(days)
        
        return jsonify({
            'code': 0,
            'message': 'success',
            'data': {
                'count': count
            }
        })
    except Exception as e:
        logger.error(f"清理PDF失败: {str(e)}")
        return jsonify({
            'code': 500,
            'message': f'清理PDF失败: {str(e)}'
        })

@bp.route('/download/<path:filename>')
def download_pdf(filename):
    """下载PDF文件"""
    try:
        # 构建PDF文件路径
        pdf_dir = os.path.join(current_app.root_path, '..', 'data', 'pdfs')
        pdf_path = os.path.join(pdf_dir, filename)
        
        # 检查文件是否存在
        if not os.path.exists(pdf_path):
            return jsonify({
                'code': 404,
                'message': 'PDF文件不存在'
            }), 404
            
        # 返回文件
        return send_file(
            pdf_path,
            as_attachment=True,
            download_name=filename,
            mimetype='application/pdf'
        )
        
    except Exception as e:
        logger.error(f"下载PDF失败: {str(e)}")
        return jsonify({
            'code': 500,
            'message': f'下载PDF失败: {str(e)}'
        }), 500

@bp.route('/api/deep-crawl', methods=['POST'])
def deep_crawl():
    """深度爬取文章API"""
    try:
        data = request.get_json()
        if not data or 'url' not in data:
            return jsonify({
                'code': 400,
                'message': '缺少必要参数'
            }), 400
            
        url = data['url']
        max_depth = data.get('max_depth', 2)
        delay = data.get('delay', 1.0)
        
        # 创建深度爬虫实例
        crawler = DeepCrawler(max_depth=max_depth, delay=delay)
        
        # 爬取文章
        html_contents = crawler.crawl(url)
        
        # 保存HTML文件
        html_dir = os.path.join(current_app.root_path, '..', 'data', 'articles')
        html_files = crawler.save_html_content(html_contents, html_dir)
        
        # 转换为PDF
        pdf_dir = os.path.join(current_app.root_path, '..', 'data', 'pdfs')
        pdf_converter = PDFConverter()
        pdf_files = pdf_converter.batch_convert(html_files, pdf_dir)
        
        # 保存到数据库
        conn = sqlite3.connect(os.path.join(current_app.root_path, '..', 'data', 'app.db'))
        cursor = conn.cursor()
        
        for url, content in html_contents.items():
            # 从HTML中提取标题
            soup = BeautifulSoup(content, 'html.parser')
            title = soup.title.string if soup.title else url
            
            # 插入数据库
            cursor.execute('''
                INSERT INTO articles (title, content, content_url, author, create_time)
                VALUES (?, ?, ?, ?, datetime('now'))
            ''', (title, content, url, '微信公众号'))
            
        conn.commit()
        conn.close()
        
        return jsonify({
            'code': 0,
            'message': 'success',
            'data': {
                'html_files': html_files,
                'pdf_files': pdf_files
            }
        })
        
    except Exception as e:
        logger.error(f"深度爬取失败: {str(e)}")
        return jsonify({
            'code': 500,
            'message': f'深度爬取失败: {str(e)}'
        }), 500

@bp.route('/api/database/clean', methods=['POST'])
def clean_database():
    """清理数据库"""
    try:
        # 获取请求参数
        data = request.get_json()
        days = data.get('days', 7)  # 默认清理7天前的数据
        
        # 连接数据库
        db_path = os.path.join(current_app.root_path, '..', 'data', 'app.db')
        conn = sqlite3.connect(db_path)
        cursor = conn.cursor()
        
        # 获取要删除的文章
        cursor.execute('''
            SELECT id, pdf_path
            FROM articles
            WHERE datetime(create_time) < datetime('now', ?)
        ''', (f'-{days} days',))
        
        deleted_articles = cursor.fetchall()
        
        # 删除PDF文件
        pdf_dir = os.path.join(current_app.root_path, '..', 'data', 'pdfs')
        for article_id, pdf_path in deleted_articles:
            if pdf_path:
                pdf_file = os.path.join(pdf_dir, pdf_path)
                if os.path.exists(pdf_file):
                    os.remove(pdf_file)
        
        # 删除数据库记录
        cursor.execute('''
            DELETE FROM articles
            WHERE datetime(create_time) < datetime('now', ?)
        ''', (f'-{days} days',))
        
        # 清理HTML文件
        html_dir = os.path.join(current_app.root_path, '..', 'data', 'articles')
        if os.path.exists(html_dir):
            shutil.rmtree(html_dir)
            os.makedirs(html_dir)
        
        # 提交更改
        conn.commit()
        conn.close()
        
        return jsonify({
            'code': 0,
            'message': 'success',
            'data': {
                'deleted_count': len(deleted_articles)
            }
        })
        
    except Exception as e:
        logger.error(f"清理数据库失败: {str(e)}")
        return jsonify({
            'code': 500,
            'message': f'清理数据库失败: {str(e)}'
        }), 500

@bp.route('/api/articles/urls', methods=['GET'])
def get_article_urls():
    """获取文章URL列表"""
    try:
        # 连接数据库
        db_path = os.path.join(current_app.root_path, '..', 'data', 'app.db')
        conn = sqlite3.connect(db_path)
        cursor = conn.cursor()
        
        # 获取所有文章URL
        cursor.execute('''
            SELECT id, title, content_url
            FROM articles
            WHERE content_url IS NOT NULL
            ORDER BY create_time DESC
        ''')
        
        articles = []
        for row in cursor.fetchall():
            articles.append({
                'id': row[0],
                'title': row[1],
                'url': row[2]
            })
        
        conn.close()
        
        return jsonify({
            'code': 0,
            'message': 'success',
            'data': articles
        })
        
    except Exception as e:
        logger.error(f"获取文章URL列表失败: {str(e)}")
        return jsonify({
            'code': 500,
            'message': f'获取文章URL列表失败: {str(e)}'
        }), 500

@bp.route('/preview/<int:article_id>')
def preview_article(article_id):
    """预览文章
    
    Args:
        article_id (int): 文章ID
        
    Returns:
        str: HTML页面
    """
    try:
        # 连接数据库
        conn = sqlite3.connect(os.path.join(current_app.root_path, '..', 'data', 'app.db'))
        conn.row_factory = sqlite3.Row
        cursor = conn.cursor()
        
        # 查询文章
        cursor.execute('''
            SELECT title, content, author, create_time, content_url, pdf_path
            FROM articles
            WHERE id = ?
        ''', (article_id,))
        
        row = cursor.fetchone()
        if not row:
            conn.close()
            return jsonify({'error': '文章不存在'}), 404
            
        article = {
            'title': row['title'],
            'content': row['content'],
            'author': row['author'],
            'create_time': row['create_time'],
            'content_url': row['content_url'],
            'pdf_path': row['pdf_path']
        }
        
        conn.close()
        
        # 生成预览HTML
        html_content = f'''<!DOCTYPE html>
<html lang="zh-CN">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>{article['title']} - 文章预览</title>
    <link href="/static/css/bootstrap.min.css" rel="stylesheet">
    <link href="/static/css/all.min.css" rel="stylesheet">
    <style>
        body {{
            font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif;
            line-height: 1.6;
            color: #333;
            background-color: #f8f9fa;
            padding: 20px;
        }}
        .container {{
            max-width: 1000px;
            margin: 0 auto;
            background: white;
            padding: 30px;
            border-radius: 10px;
            box-shadow: 0 2px 4px rgba(0,0,0,0.1);
        }}
        .article-header {{
            margin-bottom: 30px;
            padding-bottom: 20px;
            border-bottom: 1px solid #eee;
        }}
        .article-title {{
            font-size: 28px;
            font-weight: bold;
            color: #2c3e50;
            margin-bottom: 15px;
        }}
        .article-meta {{
            color: #666;
            font-size: 14px;
        }}
        .article-meta i {{
            margin-right: 5px;
            color: #007bff;
        }}
        .article-content {{
            font-size: 16px;
            line-height: 1.8;
        }}
        /* 覆盖微信文章的隐藏样式 */
        .article-content .rich_media_content {{
            visibility: visible !important;
            opacity: 1 !important;
        }}
        .article-content section {{
            margin-bottom: 1em;
        }}
        .article-content span[leaf] {{
            display: block;
            margin-bottom: 0.5em;
        }}
        .article-content img {{
            max-width: 100%;
            height: auto;
            margin: 15px 0;
            border-radius: 5px;
        }}
        .article-content p {{
            margin-bottom: 1.2em;
        }}
        .article-content h1, 
        .article-content h2, 
        .article-content h3, 
        .article-content h4, 
        .article-content h5, 
        .article-content h6 {{
            margin-top: 1.5em;
            margin-bottom: 0.8em;
            color: #2c3e50;
        }}
        .article-content blockquote {{
            border-left: 4px solid #007bff;
            padding-left: 15px;
            margin-left: 0;
            color: #666;
            font-style: italic;
        }}
        .article-content pre {{
            background: #f8f9fa;
            padding: 15px;
            border-radius: 5px;
            overflow-x: auto;
        }}
        .article-content code {{
            background: #f8f9fa;
            padding: 2px 5px;
            border-radius: 3px;
            font-family: Consolas, Monaco, 'Andale Mono', monospace;
        }}
        .article-content table {{
            width: 100%;
            border-collapse: collapse;
            margin: 15px 0;
        }}
        .article-content table th,
        .article-content table td {{
            border: 1px solid #dee2e6;
            padding: 8px;
        }}
        .article-content table th {{
            background: #f8f9fa;
        }}
        .article-footer {{
            margin-top: 30px;
            padding-top: 20px;
            border-top: 1px solid #eee;
            color: #666;
            font-size: 14px;
        }}
        .back-link {{
            display: inline-flex;
            align-items: center;
            gap: 5px;
            padding: 8px 16px;
            border-radius: 5px;
            background: #007bff;
            color: white;
            text-decoration: none;
            transition: background-color 0.2s;
            margin-bottom: 20px;
        }}
        .back-link:hover {{
            background: #0056b3;
            color: white;
        }}
        .action-buttons {{
            margin-top: 20px;
            display: flex;
            gap: 10px;
        }}
        .action-buttons .btn {{
            display: inline-flex;
            align-items: center;
            gap: 5px;
        }}
        @media (max-width: 768px) {{
            .container {{
                padding: 15px;
            }}
            .article-title {{
                font-size: 24px;
            }}
            .action-buttons {{
                flex-direction: column;
            }}
            .action-buttons .btn {{
                width: 100%;
            }}
        }}
    </style>
</head>
<body>
    <div class="container">
        <a href="/" class="back-link">
            <i class="fas fa-arrow-left"></i> 返回首页
        </a>
        
        <div class="article-header">
            <h1 class="article-title">{article['title']}</h1>
            <div class="article-meta">
                <span><i class="fas fa-user"></i> {article['author']}</span>
                <span class="ms-3"><i class="fas fa-clock"></i> {article['create_time']}</span>
            </div>
        </div>
        
        <div class="article-content">
            {article['content']}
        </div>
        
        <div class="article-footer">
            <p>原文链接：<a href="{article['content_url']}" target="_blank">{article['content_url']}</a></p>
            <div class="action-buttons">
                <button onclick="generatePDF({article_id})" class="btn btn-primary" id="generatePdfBtn">
                    <i class="fas fa-file-pdf"></i> 生成PDF
                </button>
                {f'<a href="/download/{article["pdf_path"]}" class="btn btn-success"><i class="fas fa-download"></i> 下载PDF</a>' if article['pdf_path'] else ''}
            </div>
        </div>
    </div>
    
    <script src="/static/js/bootstrap.bundle.min.js"></script>
    <script src="/static/js/jquery.min.js"></script>
    <script>
        function showMessage(message, type = 'info') {{
            const alertHtml = `
                <div class="alert alert-${{type}} alert-dismissible fade show" role="alert">
                    ${{message}}
                    <button type="button" class="btn-close" data-bs-dismiss="alert" aria-label="Close"></button>
                </div>
            `;
            $('.container').prepend(alertHtml);
        }}

        function generatePDF(articleId) {{
            const btn = document.getElementById('generatePdfBtn');
            btn.disabled = true;
            btn.innerHTML = '<i class="fas fa-spinner fa-spin"></i> 生成中...';
            
            $.ajax({{
                url: `/api/generate-pdf/${{articleId}}`,
                method: 'POST',
                success: function(response) {{
                    if (response.code === 0) {{
                        showMessage('PDF生成成功！', 'success');
                        setTimeout(() => window.location.reload(), 1500);
                    }} else {{
                        showMessage(response.message || '生成PDF失败', 'danger');
                        btn.disabled = false;
                        btn.innerHTML = '<i class="fas fa-file-pdf"></i> 生成PDF';
                    }}
                }},
                error: function(xhr) {{
                    showMessage(xhr.responseJSON?.message || '服务器错误', 'danger');
                    btn.disabled = false;
                    btn.innerHTML = '<i class="fas fa-file-pdf"></i> 生成PDF';
                }}
            }});
        }}
    </script>
</body>
</html>'''
        
        return html_content
        
    except Exception as e:
        current_app.logger.error(f"预览文章失败: {str(e)}")
        return jsonify({'error': '预览文章失败'}), 500

@bp.route('/export/pdf/<int:article_id>')
def export_pdf(article_id):
    """导出文章为PDF
    
    Args:
        article_id (int): 文章ID
        
    Returns:
        Response: PDF文件
    """
    try:
        # 从数据库获取文章
        article = Article.query.get_or_404(article_id)
        
        # 生成PDF
        pdf_service = PDFService()
        pdf_path = pdf_service.generate_pdf(article.title, article.content)
        
        if not pdf_path:
            return jsonify({'error': '生成PDF失败'}), 500
            
        # 返回PDF文件
        return send_file(
            pdf_path,
            as_attachment=True,
            download_name=f"{article.title}.pdf",
            mimetype='application/pdf'
        )
        
    except Exception as e:
        current_app.logger.error(f"导出PDF失败: {str(e)}")
        return jsonify({'error': '导出PDF失败'}), 500

@bp.route('/articles/preview')
def preview_articles():
    """预览所有文章"""
    try:
        # 获取分页参数
        page = request.args.get('page', 1, type=int)
        per_page = request.args.get('per_page', 10, type=int)  # 修改为10篇每页，便于阅读
        
        # 连接数据库
        db_path = os.path.join(current_app.root_path, '..', 'data', 'app.db')
        conn = sqlite3.connect(db_path)
        cursor = conn.cursor()
        
        # 获取总文章数
        cursor.execute('SELECT COUNT(*) FROM articles')
        total = cursor.fetchone()[0]
        
        # 计算偏移量
        offset = (page - 1) * per_page
        
        # 获取分页文章
        cursor.execute('''
            SELECT id, title, content, author, create_time, content_url, pdf_path
            FROM articles
            ORDER BY create_time DESC
            LIMIT ? OFFSET ?
        ''', (per_page, offset))
        
        articles = []
        for row in cursor.fetchall():
            # 截取内容预览
            content_preview = row[2][:150] + '...' if row[2] and len(row[2]) > 150 else row[2]
            
            articles.append({
                'id': row[0],
                'title': row[1],
                'content_preview': content_preview,
                'author': row[3],
                'create_time': row[4],
                'content_url': row[5],
                'pdf_path': row[6]
            })
        
        conn.close()
        
        # 计算总页数
        total_pages = (total + per_page - 1) // per_page
        
        # 生成文章列表HTML
        article_rows = []
        for article in articles:
            row = f'''
<tr>
    <td class="align-middle">
        <div class="article-title">{article['title']}</div>
        <div class="article-meta">
            <span><i class="fas fa-user"></i> {article['author']}</span>
            <span class="ms-3"><i class="fas fa-clock"></i> {article['create_time']}</span>
        </div>
    </td>
    <td class="align-middle">
        <div class="article-content">{article['content_preview']}</div>
    </td>
    <td class="align-middle">
        <div class="article-actions">
            <a href="/preview/{article['id']}" class="btn btn-sm btn-primary mb-2" target="_blank">
                <i class="fas fa-eye"></i> 查看详情
            </a>
            {f'<a href="/download/{article["pdf_path"]}" class="btn btn-sm btn-success mb-2"><i class="fas fa-file-pdf"></i> 下载PDF</a>' if article['pdf_path'] else ''}
            <a href="{article['content_url']}" class="btn btn-sm btn-info" target="_blank">
                <i class="fas fa-external-link-alt"></i> 原文链接
            </a>
        </div>
    </td>
</tr>'''
            article_rows.append(row)
        
        # 生成分页HTML
        pagination = ''
        if total_pages > 1:
            page_items = []
            # 添加上一页按钮
            if page > 1:
                page_items.append(f'''
<li class="page-item">
    <a class="page-link" href="?page={page-1}" aria-label="Previous">
        <span aria-hidden="true">&laquo;</span>
    </a>
</li>''')
            
            # 添加页码按钮
            for p in range(1, total_pages + 1):
                if p == 1 or p == total_pages or (p >= page - 2 and p <= page + 2):
                    page_items.append(f'''
<li class="page-item {'active' if p == page else ''}">
    <a class="page-link" href="?page={p}">{p}</a>
</li>''')
                elif p == page - 3 or p == page + 3:
                    page_items.append('''
<li class="page-item disabled">
    <span class="page-link">...</span>
</li>''')
            
            # 添加下一页按钮
            if page < total_pages:
                page_items.append(f'''
<li class="page-item">
    <a class="page-link" href="?page={page+1}" aria-label="Next">
        <span aria-hidden="true">&raquo;</span>
    </a>
</li>''')
            
            pagination = f'''
<nav aria-label="Page navigation" class="mt-4">
    <ul class="pagination justify-content-center">
        {''.join(page_items)}
    </ul>
</nav>'''
        
        # 生成完整HTML页面
        html_content = f'''
<!DOCTYPE html>
<html lang="zh-CN">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>文章预览 - 微信公众号文章采集系统</title>
    <link href="/static/css/bootstrap.min.css" rel="stylesheet">
    <link href="/static/css/all.min.css" rel="stylesheet">
    <style>
        body {{
            font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif;
            line-height: 1.6;
            color: #333;
            background-color: #f8f9fa;
            padding: 20px 0;
        }}
        .container {{
            max-width: 1400px;
        }}
        .page-header {{
            background: white;
            padding: 20px;
            border-radius: 10px;
            box-shadow: 0 2px 4px rgba(0,0,0,0.1);
            margin-bottom: 30px;
        }}
        .table-container {{
            background: white;
            border-radius: 10px;
            box-shadow: 0 2px 4px rgba(0,0,0,0.1);
            padding: 20px;
            margin-bottom: 30px;
        }}
        .table {{
            margin-bottom: 0;
        }}
        .table th {{
            background-color: #f8f9fa;
            border-bottom: 2px solid #dee2e6;
            color: #495057;
            font-weight: 600;
            padding: 15px;
        }}
        .table td {{
            padding: 15px;
            vertical-align: middle;
            border-bottom: 1px solid #dee2e6;
        }}
        .table tr:last-child td {{
            border-bottom: none;
        }}
        .article-title {{
            font-size: 16px;
            font-weight: bold;
            color: #2c3e50;
            margin-bottom: 8px;
        }}
        .article-meta {{
            color: #666;
            font-size: 13px;
        }}
        .article-meta i {{
            margin-right: 5px;
            color: #007bff;
        }}
        .article-content {{
            color: #666;
            font-size: 14px;
            line-height: 1.5;
        }}
        .article-actions {{
            display: flex;
            flex-direction: column;
            gap: 8px;
        }}
        .article-actions .btn {{
            width: 100%;
            display: flex;
            align-items: center;
            justify-content: center;
            gap: 5px;
        }}
        .pagination {{
            margin-top: 30px;
        }}
        .pagination .page-link {{
            color: #007bff;
            border: none;
            margin: 0 2px;
            border-radius: 5px;
        }}
        .pagination .page-item.active .page-link {{
            background-color: #007bff;
            color: white;
        }}
        .pagination .page-item.disabled .page-link {{
            color: #6c757d;
        }}
        .back-link {{
            margin-bottom: 20px;
            display: inline-flex;
            align-items: center;
            gap: 5px;
            padding: 8px 16px;
            border-radius: 5px;
            background: #007bff;
            color: white;
            text-decoration: none;
            transition: background-color 0.2s;
        }}
        .back-link:hover {{
            background: #0056b3;
            color: white;
        }}
        @media (max-width: 768px) {{
            .table-responsive {{
                margin: 0 -20px;
            }}
            .article-actions .btn {{
                padding: 0.25rem 0.5rem;
                font-size: 0.875rem;
            }}
        }}
    </style>
</head>
<body>
    <div class="container">
        <div class="page-header">
            <div class="d-flex justify-content-between align-items-center">
                <div>
                    <h1 class="h3 mb-0">文章预览</h1>
                    <p class="text-muted mb-0">共 {total} 篇文章</p>
                </div>
                <a href="/" class="back-link">
                    <i class="fas fa-arrow-left"></i> 返回首页
                </a>
            </div>
        </div>
        
        <div class="table-container">
            <div class="table-responsive">
                <table class="table">
                    <thead>
                        <tr>
                            <th style="width: 30%">标题信息</th>
                            <th style="width: 50%">内容预览</th>
                            <th style="width: 20%">操作</th>
                        </tr>
                    </thead>
                    <tbody>
                        {''.join(article_rows)}
                    </tbody>
                </table>
            </div>
        </div>
        
        {pagination}
    </div>
    
    <script src="/static/js/bootstrap.bundle.min.js"></script>
    <script src="/static/js/jquery.min.js"></script>
    <script>
        function showMessage(message, type = 'info') {{
            const alertHtml = `
                <div class="alert alert-${{type}} alert-dismissible fade show" role="alert">
                    ${{message}}
                    <button type="button" class="btn-close" data-bs-dismiss="alert" aria-label="Close"></button>
                </div>
            `;
            $('.container').prepend(alertHtml);
        }}

        function generatePDF(articleId) {{
            const btn = document.getElementById('generatePdfBtn');
            btn.disabled = true;
            btn.innerHTML = '<i class="fas fa-spinner fa-spin"></i> 生成中...';
            
            $.ajax({{
                url: `/api/generate-pdf/${{articleId}}`,
                method: 'POST',
                success: function(response) {{
                    if (response.code === 0) {{
                        showMessage('PDF生成成功！', 'success');
                        setTimeout(() => window.location.reload(), 1500);
                    }} else {{
                        showMessage(response.message || '生成PDF失败', 'danger');
                        btn.disabled = false;
                        btn.innerHTML = '<i class="fas fa-file-pdf"></i> 生成PDF';
                    }}
                }},
                error: function(xhr) {{
                    showMessage(xhr.responseJSON?.message || '服务器错误', 'danger');
                    btn.disabled = false;
                    btn.innerHTML = '<i class="fas fa-file-pdf"></i> 生成PDF';
                }}
            }});
        }}
    </script>
</body>
</html>'''
        
        return html_content
        
    except Exception as e:
        logger.error(f"生成文章预览页面失败: {str(e)}")
        return jsonify({
            'code': 500,
            'message': f'生成文章预览页面失败: {str(e)}'
        }), 500 

@bp.route('/api/articles/<int:article_id>/content', methods=['GET'])
def get_article_content(article_id):
    """获取文章内容
    
    Args:
        article_id (int): 文章ID
        
    Returns:
        json: 文章内容
    """
    try:
        # 连接数据库
        conn = sqlite3.connect(os.path.join(current_app.root_path, '..', 'data', 'app.db'))
        conn.row_factory = sqlite3.Row
        cursor = conn.cursor()
        
        # 查询文章
        cursor.execute('''
            SELECT title, content, author, create_time
            FROM articles
            WHERE id = ?
        ''', (article_id,))
        
        row = cursor.fetchone()
        if not row:
            conn.close()
            return jsonify({
                'code': 404,
                'message': '文章不存在'
            }), 404
            
        article = {
            'title': row['title'],
            'content': row['content'],
            'author': row['author'],
            'create_time': row['create_time']
        }
        
        conn.close()
        
        # 生成带样式的HTML内容
        html_content = f'''
        <div class="article-header mb-4">
            <h2 class="article-title">{article['title']}</h2>
            <div class="article-meta text-muted">
                <span><i class="fas fa-user"></i> {article['author']}</span>
                <span class="ms-3"><i class="fas fa-clock"></i> {article['create_time']}</span>
            </div>
        </div>
        <div class="article-content">
            {article['content']}
        </div>
        '''
        
        return jsonify({
            'code': 0,
            'message': 'success',
            'data': {
                'content': html_content
            }
        })
        
    except Exception as e:
        current_app.logger.error(f"获取文章内容失败: {str(e)}")
        return jsonify({
            'code': 500,
            'message': f'获取文章内容失败: {str(e)}'
        }), 500 

@bp.route('/content/<int:article_id>')
def view_article_content(article_id):
    """查看文章原文内容
    
    Args:
        article_id (int): 文章ID
        
    Returns:
        str: HTML页面
    """
    try:
        # 连接数据库
        conn = sqlite3.connect(os.path.join(current_app.root_path, '..', 'data', 'app.db'))
        conn.row_factory = sqlite3.Row
        cursor = conn.cursor()
        
        # 查询文章
        cursor.execute('''
            SELECT title, content, author, create_time, content_url
            FROM articles
            WHERE id = ?
        ''', (article_id,))
        
        row = cursor.fetchone()
        if not row:
            conn.close()
            return jsonify({'error': '文章不存在'}), 404
            
        article = {
            'title': row['title'],
            'content': row['content'],
            'author': row['author'],
            'create_time': row['create_time'],
            'content_url': row['content_url']
        }
        
        conn.close()
        
        # 生成HTML页面
        html_content = f'''<!DOCTYPE html>
<html lang="zh-CN">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>{article['title']} - 原文内容</title>
    <link href="/static/css/bootstrap.min.css" rel="stylesheet">
    <link href="/static/css/all.min.css" rel="stylesheet">
    <style>
        body {{
            font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif;
            line-height: 1.6;
            color: #333;
            background-color: #f8f9fa;
            padding: 20px;
        }}
        .container {{
            max-width: 1000px;
            margin: 0 auto;
            background: white;
            padding: 30px;
            border-radius: 10px;
            box-shadow: 0 2px 4px rgba(0,0,0,0.1);
        }}
        .article-header {{
            margin-bottom: 30px;
            padding-bottom: 20px;
            border-bottom: 1px solid #eee;
        }}
        .article-title {{
            font-size: 28px;
            font-weight: bold;
            color: #2c3e50;
            margin-bottom: 15px;
        }}
        .article-meta {{
            color: #666;
            font-size: 14px;
        }}
        .article-meta i {{
            margin-right: 5px;
            color: #007bff;
        }}
        .article-content {{
            font-size: 16px;
            line-height: 1.8;
        }}
        .article-content img {{
            max-width: 100%;
            height: auto;
            margin: 15px 0;
            border-radius: 5px;
        }}
        .article-content p {{
            margin-bottom: 1.2em;
        }}
        .article-footer {{
            margin-top: 30px;
            padding-top: 20px;
            border-top: 1px solid #eee;
            color: #666;
            font-size: 14px;
        }}
        .back-link {{
            display: inline-flex;
            align-items: center;
            gap: 5px;
            padding: 8px 16px;
            border-radius: 5px;
            background: #007bff;
            color: white;
            text-decoration: none;
            transition: background-color 0.2s;
            margin-bottom: 20px;
        }}
        .back-link:hover {{
            background: #0056b3;
            color: white;
        }}
        @media (max-width: 768px) {{
            .container {{
                padding: 15px;
            }}
            .article-title {{
                font-size: 24px;
            }}
        }}
    </style>
</head>
<body>
    <div class="container">
        <a href="/" class="back-link">
            <i class="fas fa-arrow-left"></i> 返回首页
        </a>
        
        <div class="article-header">
            <h1 class="article-title">{article['title']}</h1>
            <div class="article-meta">
                <span><i class="fas fa-user"></i> {article['author']}</span>
                <span class="ms-3"><i class="fas fa-clock"></i> {article['create_time']}</span>
            </div>
        </div>
        
        <div class="article-content">
            {article['content']}
        </div>
        
        <div class="article-footer">
            <p>原文链接：<a href="{article['content_url']}" target="_blank">{article['content_url']}</a></p>
        </div>
    </div>
    
    <script src="/static/js/bootstrap.bundle.min.js"></script>
</body>
</html>'''
        
        return html_content
        
    except Exception as e:
        current_app.logger.error(f"查看文章内容失败: {str(e)}")
        return jsonify({'error': '查看文章内容失败'}), 500 